import math


def calculate_bearing(lat1, lon1, lat2, lon2):
    """
    计算A点（lat1, lon1）到B点（lat2, lon2）的方位角（度）
    :return: 方位角（0-360°，正北为0°，顺时针旋转）
    """
    # 将经纬度转换为弧度
    lat1_rad = math.radians(lat1)
    lon1_rad = math.radians(lon1)
    lat2_rad = math.radians(lat2)
    lon2_rad = math.radians(lon2)

    # 计算经度差
    dlon = lon2_rad - lon1_rad

    # 计算方位角的sin和cos值
    y = math.sin(dlon) * math.cos(lat2_rad)
    x = math.cos(lat1_rad) * math.sin(lat2_rad) - math.sin(lat1_rad) * math.cos(
        lat2_rad
    ) * math.cos(dlon)
    bearing_rad = math.atan2(y, x)

    # 转换为度并调整到0-360°范围
    bearing_deg = math.degrees(bearing_rad)
    bearing_deg = (bearing_deg + 360) % 360  # 确保结果为正

    return bearing_deg


def get_orientation_with_degree(lat1, lon1, lat2, lon2):
    """
    获取带角度的方位描述（如“东偏南15°”）
    """
    bearing = calculate_bearing(lat1, lon1, lat2, lon2)
    direction = ""

    # 将方位角转换为方向描述
    if 22.5 <= bearing < 67.5:
        direction = "东北"
    elif 67.5 <= bearing < 112.5:
        direction = "东"
    elif 112.5 <= bearing < 157.5:
        direction = "东南"
    elif 157.5 <= bearing < 202.5:
        direction = "南"
    elif 202.5 <= bearing < 247.5:
        direction = "西南"
    elif 247.5 <= bearing < 292.5:
        direction = "西"
    elif 292.5 <= bearing < 337.5:
        direction = "西北"
    else:
        direction = "北"

    # 计算偏角（相对于主方向的偏移角度）
    if direction == "北":
        angle = min(bearing, 360 - bearing)
        offset = "南" if bearing > 180 else "北"
    elif direction == "东":
        angle = min(bearing - 90, 270 - bearing)
        offset = "西" if bearing < 180 else "东"
    elif direction == "南":
        angle = min(bearing - 180, 360 - (bearing - 180))
        offset = "北" if bearing > 270 else "南"
    elif direction == "西":
        angle = min(360 - bearing, bearing - 270)
        offset = "东" if bearing < 270 else "西"
    else:  # 东北、东南、西南、西北
        if direction == "东北":
            base_angle = 45
        elif direction == "东南":
            base_angle = 135
        elif direction == "西南":
            base_angle = 225
        else:  # 西北
            base_angle = 315
        angle = abs(bearing - base_angle)
        offset1 = "北" if base_angle < 90 or base_angle > 270 else "南"
        offset2 = "东" if base_angle < 180 else "西"
        return f"{offset1}{offset2}偏{['东', '南', '西', '北'][int(angle//45)]}{angle:.1f}°"

    # 组合主方向和偏角描述
    return f"{direction}偏{offset}{angle:.1f}°" if angle > 0 else direction


def calculate_distance(lat1, lon1, lat2, lon2):
    """
    计算两个经纬度坐标之间的球面距离（千米）
    :param lat1: 点1纬度（十进制）
    :param lon1: 点1经度（十进制）
    :param lat2: 点2纬度（十进制）
    :param lon2: 点2经度（十进制）
    :return: 距离（千米）
    """
    # 地球半径（千米）
    R = 6371.0

    # 将经纬度转换为弧度
    lat1_rad = math.radians(lat1)
    lon1_rad = math.radians(lon1)
    lat2_rad = math.radians(lat2)
    lon2_rad = math.radians(lon2)

    # 计算经纬度差值
    dlon = lon2_rad - lon1_rad
    dlat = lat2_rad - lat1_rad

    # Haversine公式
    a = (
        math.sin(dlat / 2) ** 2
        + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon / 2) ** 2
    )
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    distance = R * c

    return distance


if __name__ in {"__main__", "__mp_main__"}:
    # 示例：计算北京和上海的直线距离
    # 北京经纬度：39.9042° N, 116.4074° E
    # 上海经纬度：31.2304° N, 121.4737° E
    beijing_lat, beijing_lon = 39.9042, 116.4074
    shanghai_lat, shanghai_lon = 31.2304, 121.4737

    distance = calculate_distance(beijing_lat, beijing_lon, shanghai_lat, shanghai_lon)
    print(f"北京到上海的直线距离约为：{distance:.2f} 千米")
    angle = calculate_bearing(beijing_lat, beijing_lon, shanghai_lat, shanghai_lon)
    print(f"北京到上海的方位角为：{angle:.2f}")
    orientation = get_orientation_with_degree(
        beijing_lat, beijing_lon, shanghai_lat, shanghai_lon
    )
    print(f"北京到上海的方向为：{orientation}")
    orientation2 = get_orientation_with_degree(
        shanghai_lat, shanghai_lon, beijing_lat, beijing_lon
    )
    print(f"上海到北京的方向为：{orientation2}")
